//
//  File.swift
//  
//
//  Created by 钟城广 on 2022/8/30.
//

import Foundation
import CoreBluetooth
import SwiftUI

public typealias TransactionResultCallback = (_ result:Bool,_ errorMessage: String?)->Void

public typealias TransactionProgressCallback = (_ progress:Float)->Void

public class OtaTransaction : NSObject{
    
    internal var initlallizer: DeviceInitializer!
    private var updating = false
    private var lock = NSLock()//防抖
    
    // MARK: 单例
    private static let core:OtaTransaction = {
        let shared = OtaTransaction()
        return shared
    }()
    
    public override init() {
        super.init()
        initlallizer = DeviceInitializer()
    }
    
    public class func shared() -> OtaTransaction {
        return core
    }
    
    private var targetIdentifier: UUID? = nil
    public func startTransaction(identifier: UUID, fastMode: Bool, cb: @escaping TransactionResultCallback) {
        targetIdentifier = identifier
        cb(true,nil)
    }
    
    public func execute(otaTask:BxOtaTask,fastMode:Bool,onProgress: @escaping TransactionProgressCallback,onResult: @escaping TransactionResultCallback){
        if(updating){
            onResult(false,"Maybe the last OTA task is not over yet")
            return
        }
        guard let id = self.targetIdentifier else{
            onResult(false,"Please call <startTransaction> first and wait success callback")
            return
        }
        if self.initlallizer.peripheral == nil || self.initlallizer.peripheral?.identifier != id || self.initlallizer.peripheral?.state != CBPeripheralState.connected{
            initlallizer.findAndSetupPeripheral(identifier: id, callback: { (res,err) in
                if res {
                    self.innerExecute(otaTask, fastMode, onProgress, onResult)
                }else{
                    onResult(res,err)
                }
            })
        }else{
            print(self.initlallizer.peripheral?.state.rawValue ?? 100)
            innerExecute(otaTask, fastMode, onProgress, onResult)
        }
    }
    
    private func innerExecute(
        _ otaTask:BxOtaTask,
        _ fastMode:Bool,
        _ onProgress: @escaping TransactionProgressCallback,
        _ onResult: @escaping TransactionResultCallback){
            guard let target = self.initlallizer.peripheral else{
                onResult(false,"Invalid peripheral")
                return
            }
            guard let ctrl = self.initlallizer._ctrl else{
                onResult(false,"Invalid peripheral")
                return
            }
            guard let data = self.initlallizer._data else{
                onResult(false,"Invalid peripheral")
                return
            }
            updating = true
            let basicProcess = BasicProcess(
                peripheral: target,
                ctrl: ctrl,
                data: data,
                index: 0,
                task: otaTask,
                fastMode: fastMode
            )
            basicProcess.start(){ state in
                let inProgress = state.startTime > 0 && state.endTime == 0
                if(inProgress){
                    onProgress(state.progress)
                }
                let end = state.startTime > 0 && state.endTime > 0
                if(end){
                    self.updating = false
                    let errorMsg = state.errorMessage ?? "Unknown Error"
                    onResult(state.result,errorMsg)
                }
            }
        }
    
    
    public func endTransaction(fastMode: Bool) {
        if fastMode && initlallizer._ctrl != nil{
            var cmd = Data()
            cmd.append(UInt8(0x0B))
            initlallizer.peripheral?.writeValue(cmd, for: initlallizer._ctrl!,type: .withResponse)
        }
        targetIdentifier = nil
    }
    
}
